package com.york.tinyrpc.protoss;

import com.york.tinyrpc.protoss.config.RegistryCenterConfig;
import com.york.tinyrpc.protoss.config.TinyRpcConfig;
import com.york.tinyrpc.protoss.constant.TinyRpcConstants;
import com.york.tinyrpc.protoss.registry.center.RegistryCenter;
import com.york.tinyrpc.protoss.registry.center.RegistryCenterFactory;
import com.york.tinyrpc.protoss.utils.ConfigUtils;
import lombok.extern.slf4j.Slf4j;

/**
 * TinyRPC 框架启动
 * 启动时初始化配置信息，通过读取配置信息的方式，将需要调用API的信息传入
 * 使用双检锁-单例模式实现
 */
@Slf4j
public class TinyRpcApplication {

    private static volatile TinyRpcConfig rpcConfig;

    /**
     * 框架初始化，支持传入自定义配置
     * todo protoss版本：我们设置了消费方和提供方与注册中心的SPI机制配置化方式的建立连接，在此需要注册中心的初始化操作
     * 注册中心初始化已完成
     *
     * @param newRpcConfig
     */
    public static void init(TinyRpcConfig newRpcConfig) {
        rpcConfig = newRpcConfig;
        log.info("TinyRPC init..., config: {}", newRpcConfig.toString());
        // 通过RPC的配置获取注册中心的配置项，于是初始化注册中心
        RegistryCenterConfig registryCenterConfig = rpcConfig.getRegistryCenterConfig();
        RegistryCenter registryCenter = RegistryCenterFactory.getRegistryCenterByType(
                registryCenterConfig.getRegistryCenterType());
        registryCenter.registryCenterInit(registryCenterConfig);
        log.info("RegistryCenter init..., config:{}", registryCenterConfig);

        // 创建并注册ShutdownHook，在JVM退出前执行注册中心下线流程（将对应服务节点及时清楚注册信息）
        Runtime.getRuntime().addShutdownHook(new Thread(registryCenter::destroyRegistryCenter));
    }

    /**
     * 初始化
     */
    public static void init() {
        TinyRpcConfig newRpcConfig;
        try {
            newRpcConfig = ConfigUtils.loadConfig(TinyRpcConfig.class, TinyRpcConstants.DEFAULT_CONFIG_PREFIX);
        } catch (Exception e) {
            // 配置加载失败，使用默认值
            newRpcConfig = new TinyRpcConfig();
        }
        init(newRpcConfig);
    }

    /**
     * 获取配置
     * 双重检查锁
     */
    public static TinyRpcConfig getRpcConfig() {
        if (rpcConfig == null) {
            synchronized (TinyRpcConfig.class) {
                if (rpcConfig == null) {
                    init();
                }
            }
        }
        return rpcConfig;
    }
}


